package org.lemon.transport.http.service;

import com.google.gson.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.lemon.transport.http.service.callback.DeviceAuthCallback;
import org.lemon.transport.context.adaptor.JsonConverter;
import org.lemon.transport.context.data.device.DeviceTransportType;
import org.server.transport.gen.TransportProto;
import org.lemon.transport.context.service.TransportServiceCallback;
import org.lemon.transport.context.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class DeviceTransportService {

    @Autowired
    private HttpTransportContext transportContext;

    /**
     * 获取设备属性值
     *
     * @param deviceToken
     * @param clientKeys
     * @param sharedKeys
     * @return
     */
    public DeferredResult<ResponseEntity<String>> getDeviceAttributes(String deviceToken, String clientKeys, String sharedKeys) {

        DeferredResult<ResponseEntity<String>> responseWriter = new DeferredResult<>();
        transportContext.getTransportService()
                .deviceTokenValidate(DeviceTransportType.DEFAULT, deviceToken, new DeviceAuthCallback<>(transportContext, responseWriter, (sessionInfo) -> {
                    TransportProto.GetAttributeRequestMsg.Builder request = TransportProto.GetAttributeRequestMsg.newBuilder().setRequestId(0);
                    List<String> clientKeySet = !StringUtils.isNullOrEmpty(clientKeys) ? Arrays.asList(clientKeys.split(",")) : null;
                    List<String> sharedKeySet = !StringUtils.isNullOrEmpty(sharedKeys) ? Arrays.asList(sharedKeys.split(",")) : null;
                    if (clientKeySet != null) {
                        request.addAllClientAttributeNames(clientKeySet);
                    }
                    if (sharedKeySet != null) {
                        request.addAllSharedAttributeNames(sharedKeySet);
                    }
                }));

        return responseWriter;
    }

    /**
     * 提交设备属性值
     * 请求示例:
     *
     * @param deviceToken
     * @param json
     * @return
     */
    public DeferredResult<ResponseEntity<Void>> postDeviceAttributes(String deviceToken, String json) {

        DeferredResult<ResponseEntity<Void>> responseWriter = new DeferredResult<>();
        transportContext.getTransportService()
                .deviceTokenValidate(DeviceTransportType.DEFAULT, deviceToken, new DeviceAuthCallback<>(transportContext, responseWriter, (sessionInfo) -> {
                    TransportProto.PostAttributeMsg postAttributeMsg = JsonConverter.convertToAttributesProto(JsonParser.parseString(json));
                    transportContext.getTransportService()
                            .process(sessionInfo, postAttributeMsg, new HttpOkCallback(responseWriter));
                }));
        return responseWriter;
    }

    /**
     * 提交设备遥测数据
     *
     * @param deviceToken
     * @param json
     * @param request
     * @return
     */
    public DeferredResult<ResponseEntity<Void>> postTelemetry(String deviceToken, String json, HttpServletRequest request) {

        DeferredResult<ResponseEntity<Void>> responseWriter = new DeferredResult<>();
        transportContext.getTransportService()
                .deviceTokenValidate(DeviceTransportType.DEFAULT, deviceToken, new DeviceAuthCallback<>(transportContext, responseWriter, (sessionInfo) -> {
                    TransportProto.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(JsonParser.parseString(json));
                    transportContext.getTransportService()
                            .process(sessionInfo, postTelemetryMsg, new HttpOkCallback(responseWriter));
                }));
        return responseWriter;
    }

    /**
     * 保存用户认领设备所需的信息
     *
     * @param deviceToken
     * @param json
     * @return
     */
    public DeferredResult<ResponseEntity<Void>> claimDevice(String deviceToken, String json) {

        DeferredResult<ResponseEntity<Void>> responseWriter = new DeferredResult<>();
        transportContext.getTransportService()
                .deviceTokenValidate(DeviceTransportType.DEFAULT, deviceToken, new DeviceAuthCallback<>(transportContext, responseWriter, (sessionInfo) -> {
                    TransportProto.ClaimDeviceMsg claimDeviceMsg = JsonConverter.convertToClaimDeviceProto(sessionInfo.getDeviceId(), JsonParser.parseString(json));

                }));
        return responseWriter;
    }

    /**
     * 交换设备凭证
     *
     * @param json
     * @return
     */
    public DeferredResult<ResponseEntity<String>> provisionDevice(String json) {

        DeferredResult<ResponseEntity<String>> responseWriter = new DeferredResult<>();
        JsonConverter.convertToProvisionRequestMsg(JsonParser.parseString(json));
        transportContext.getTransportService()
                .process(JsonConverter.convertToProvisionRequestMsg(JsonParser.parseString(json)), new TransportServiceCallback<TransportProto.ProvisionDeviceResponseMsg>() {
                    @Override
                    public void onSuccess(TransportProto.ProvisionDeviceResponseMsg msg) {
                        responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK));
                    }

                    @Override
                    public void onError(Throwable e) {
                        log.warn("Failed to process request", e);
                        responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
                    }
                });
        return responseWriter;
    }

    private static class HttpOkCallback implements TransportServiceCallback<Void> {
        private final DeferredResult<ResponseEntity<Void>> responseWriter;

        public HttpOkCallback(DeferredResult<ResponseEntity<Void>> responseWriter) {
            this.responseWriter = responseWriter;
        }

        @Override
        public void onSuccess(Void msg) {
            responseWriter.setResult(new ResponseEntity<>(HttpStatus.OK));
        }

        @Override
        public void onError(Throwable e) {
            responseWriter.setResult(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR));
        }
    }
}
